package com.jyx.game.snake;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Random;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

import com.jyx.game.snake.Direction.Dir;

public class EetroSnake {


	public static void main(String[] args) {
		SnakeFrame frame = new SnakeFrame();
		SnakePanel panel = new SnakePanel();
		PlayControl playControl = new PlayControl(panel);
		panel.setGameControl(playControl);
		// setContentPane()把panel设置为JFrame的内容面板
		frame.setContentPane(panel);
	}
}


/**
 * 坐标点辅助类 Coordinate.java
 */
class Coordinate {
	public int x;
	public int y;

	public Coordinate(int newX, int newY) {
		x = newX;
		y = newY;
	}

	public boolean equals(Coordinate other) {
		if (x == other.x && y == other.y) {
			return true;
		}
		return false;
	}

	@Override
	public String toString() {
		return "Coordinate: [" + x + "," + y + "]";
	}}

/**
 * 操作接口
 */
interface Direction {

	public class Dir {
		public static final int UP = 1;

		public static final int DOWN = 2;

		public static final int LEFT = 3;

		public static final int RIGHT = 4;
	}
}

/**
 * 实体类 Snake.java
 */
class Snake {

	// 小方块x坐标
	private int x;

	// 小方块y坐标
	private int y;

	// 宽度
	public static final int TILE_W = 10;

	// 高度
	public static final int TILE_H = 10;

	// 下一个方向
	private int mNextDirection = Dir.RIGHT;

	// 游戏是否结束
	private boolean isEnd;

	// 存放贪吃蛇
	private ArrayList<Coordinate> mSnakeTrail = new ArrayList<Coordinate>();

	// 存放豆子
	private ArrayList<Coordinate> mAppleList = new ArrayList<Coordinate>();

	public Snake() {
		initNewGame();
	}

	// 初始化新游戏
	public void initNewGame() {
		// 初始化蛇身
		mSnakeTrail.add(new Coordinate(5, 7));
		mSnakeTrail.add(new Coordinate(6, 7));
		mSnakeTrail.add(new Coordinate(7, 7));
		mSnakeTrail.add(new Coordinate(8, 7));
		mSnakeTrail.add(new Coordinate(9, 7));
		mSnakeTrail.add(new Coordinate(10, 7));

		// 初始化豆子
		mAppleList.add(new Coordinate(20, 3));

		// 设置初始状态为false
		isEnd = false;
	}

	public ArrayList<Coordinate> getmSnakeTrail() {
		return mSnakeTrail;
	}

	public ArrayList<Coordinate> getmAppleList() {
		return mAppleList;
	}

	public boolean isEnd() {
		return isEnd;
	}

	public int getmNextDirection() {
		return mNextDirection;
	}

	public void setEnd(boolean isEnd) {
		this.isEnd = isEnd;
	}

}


/**
 * 游戏界面
 * frame类 继承JFrame SnakeFrame.java
 */
class SnakeFrame extends JFrame {

	private static final long serialVersionUID = 1L;
	// 宽度
	private static final int width = 530;

	// 高度
	private static final int height = 450;

	// 高度偏移量
	private static final int offset = 15;

	public SnakeFrame() {
		init();
	}

	/**
	 * 初始化游戏界面
	 */
	private void init() {
		this.setTitle("Java版贪吃蛇_1.0");
		// frame的高度 宽度
		this.setSize(width, height);
		// 窗口居中显示
		Toolkit toolkit = Toolkit.getDefaultToolkit();
		Dimension screen = toolkit.getScreenSize();
		int w = screen.width;
		int h = screen.height;
		// 计算左上角坐标点的x y值
		this.setLocation((w - this.getWidth()) / 2,
				(h - this.getHeight()) / 2 - offset);
		// 设置默认关闭的操作
		this.setDefaultCloseOperation(EXIT_ON_CLOSE);
		// 设置窗口大小不可改变
		this.setResizable(false);
		// 设置可见性
		this.setVisible(true);

		this.setLayout(null);
	}
}

/** panel j继承JPanelSnakePanel.java */
class SnakePanel extends JPanel {

	private static final long serialVersionUID = 1L;

	// panel的宽度
	private static final int width = 400;

	// panel的高度
	private static final int height = 400;

	// 坐标点x
	private static final int x = 10;

	// 坐标点y
	private static final int y = 10;

	// 方块尺寸
	private static final int SIZE = 10;

	// 是否开启网格
	private boolean isOpen = false;

	private Snake snake;

	// 开启作弊
	private JButton girdButton;

	private JButton aboutButton;

	// 暂停 继续按钮
	private JButton PauseButton;

	// 重新开始游戏
	private JButton StartButton;

	public Snake getSnake() {
		return snake;
	}

	private ArrayList<Coordinate> mSnakeTrail = null;

	private ArrayList<Coordinate> mAppleList = null;

	public SnakePanel() {
		snake = new Snake();
		this.setLayout(null);
		StartButton = new JButton("重新开始");
		StartButton.setLocation(420, 100);
		StartButton.setSize(90, 26);
		this.add(StartButton);
		PauseButton = new JButton("暂停游戏");
		PauseButton.setLocation(420, 150);
		PauseButton.setSize(90, 26);
		this.add(PauseButton);
		girdButton = new JButton("开启网格");
		girdButton.setLocation(420, 200);
		girdButton.setSize(90, 26);
		this.add(girdButton);
		aboutButton = new JButton("关于游戏");
		aboutButton.setLocation(420, 250);
		aboutButton.setSize(90, 26);
		this.add(aboutButton);
		girdButton.addActionListener(new GirdActionListener());
		aboutButton.addActionListener(new AboutActionListerner());
	}

	class GirdActionListener implements ActionListener {
		int i = 1;
		public void actionPerformed(ActionEvent e) {
			if (i % 2 == 1) {
				girdButton.setText("关闭网格");
				isOpen = false;
				i++;
			} else if (i % 2 == 0) {
				girdButton.setText("开启网格");
				isOpen = true;
				i++;
			}
		}
	
	}

	class AboutActionListerner implements ActionListener {

		public void actionPerformed(ActionEvent e) {

		}

	}

	@Override
	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		creatGameWindow(g);
		if (snake.isEnd()) {
			paintWords(g);
		}
		// 将焦点定在Jpanel上
		this.requestFocus();
	}
	/**
	 * 安装玩家控制器
	 * 
	 * @param control
	 */
	public void setGameControl(PlayControl control) {
		this.addKeyListener(control);
	}

	private void creatGameWindow(Graphics g) {
		g.setColor(Color.BLACK);
		g.drawRect(x, y, width, height);
		g.setColor(Color.WHITE);
		g.fillRect(x + 1, y + 1, width - 1, height - 1);
		g.setColor(Color.GRAY);
		/*************** test ******************/
		paintLine(g);
		/*************** test ******************/

		mSnakeTrail = snake.getmSnakeTrail();
		mAppleList = snake.getmAppleList();
		if (mSnakeTrail == null) {
			return;
		}
		g.setColor(Color.BLACK);
		for (int i = 0; i < mSnakeTrail.size(); i++) {
			g.fillRect(this.x + mSnakeTrail.get(i).x * SIZE,
					this.y + mSnakeTrail.get(i).y * SIZE, Snake.TILE_W,
					Snake.TILE_H);
		}

		// 画豆子
		g.fillRect(this.x + mAppleList.get(0).x * SIZE,
				this.y + mAppleList.get(0).y * SIZE, Snake.TILE_W,
				Snake.TILE_H);
	}

	// 画网格
	private void paintLine(Graphics g) {
		for (int i = 1; i < 40; i++) {
			g.drawLine(this.x, i * 10 + this.y, 400 + this.x, i * 10 + this.y);
		}
		for (int i = 1; i < 40; i++) {
			g.drawLine(i * 10 + this.x, this.y, i * 10 + this.x, 400 + this.y);
		}
	}

	// 结束提示
	private void paintWords(Graphics g) {
		Font font = new Font("宋体", Font.BOLD, 64);
		g.setFont(font);
		g.setColor(Color.RED);
		g.drawString("游戏结束", 60, 220);
	}
}


/**最关键的类 控制类 PlayControl.java */
class PlayControl implements KeyListener {

	private SnakePanel panel;

	// 蛇头在list中索引
	private int headIndex;

	/**
	 * 贪吃蛇列表
	 */
	ArrayList<Coordinate> mSnakeTrail;

	/*
	 * 豆子列表
	 */
	private ArrayList<Coordinate> mAppleList;

	// 新产生的豆子
	Coordinate newCoordinate;

	private int mNextDirection;

	// 是否绘制出结束提示
	private boolean isDraw = false;

	private Random random = new Random();

	public PlayControl(SnakePanel panel) {
		this.panel = panel;

		mSnakeTrail = panel.getSnake().getmSnakeTrail();
		mAppleList = panel.getSnake().getmAppleList();
		mNextDirection = panel.getSnake().getmNextDirection();
		headIndex = mSnakeTrail.size() - 1;
		Thread thread = new Thread(runnable);
		thread.start();
	}
	// 响应键盘按下事件
	public void keyPressed(KeyEvent e) {
		if (isDraw) {
			return;
		}
		switch (e.getKeyCode()) {
			case KeyEvent.VK_UP :
				if (mNextDirection != Dir.DOWN) {
					mNextDirection = Dir.UP;
					// moveUp();
				}
				break;

			case KeyEvent.VK_DOWN :
				if (mNextDirection != Dir.UP) {
					mNextDirection = Dir.DOWN;
					// moveDown();
				}
				break;

			case KeyEvent.VK_LEFT :
				if (mNextDirection != Dir.RIGHT) {
					mNextDirection = Dir.LEFT;
					// moveLeft();
				}
				break;

			case KeyEvent.VK_RIGHT :
				if (mNextDirection != Dir.LEFT) {
					mNextDirection = Dir.RIGHT;
					// moveRight();
				}
				break;

		}
	}

	@Override
	public void keyReleased(KeyEvent e) {

	}

	@Override
	public void keyTyped(KeyEvent e) {

	}

	// 向上移动
	private void moveUp() {
		if (!isEndGame()) {
			// 每移动一次先在头部加一块 list增加一个元素
			mSnakeTrail.add(new Coordinate(mSnakeTrail.get(headIndex).x,
					mSnakeTrail.get(headIndex).y - 1));
			// 如果判断吃到豆子
			if (isEat()) {
				// 吃到豆子的处理
				afterEatApple();
			}
			// 否则 移除第一个元素
			else {
				mSnakeTrail.remove(0);
			}
			// 重新绘制
			panel.repaint();
		}
	}

	// 向下移动
	private void moveDown() {
		if (!isEndGame()) {
			mSnakeTrail.add(new Coordinate(mSnakeTrail.get(headIndex).x,
					mSnakeTrail.get(headIndex).y + 1));
			if (isEat()) {
				afterEatApple();
			} else {
				mSnakeTrail.remove(0);
			}
			panel.repaint();
		}
	}

	// 向左移动
	private void moveLeft() {
		if (!isEndGame()) {
			mSnakeTrail.add(new Coordinate(mSnakeTrail.get(headIndex).x - 1,
					mSnakeTrail.get(headIndex).y));
			if (isEat()) {
				afterEatApple();
			} else {
				mSnakeTrail.remove(0);
			}
			panel.repaint();
		}
	}

	// 向右移动
	private void moveRight() {
		if (!isEndGame()) {
			mSnakeTrail.add(new Coordinate(mSnakeTrail.get(headIndex).x + 1,
					mSnakeTrail.get(headIndex).y));
			if (isEat()) {
				afterEatApple();
			} else {
				mSnakeTrail.remove(0);
			}
			panel.repaint();
		}
	}

	// 增加一个坐标点到存放蛇的list 添加到list的末尾
	private void afterEatApple() {
		// 每增加一个索引值加1 重新开始游戏时要回复初始值
		headIndex++;
		mAppleList.add(new Coordinate(random.nextInt(40), random.nextInt(40)));
		mAppleList.remove(0);
		newCoordinate = mAppleList.get(0);
		// System.out.println("蛇身长度:"+mSnakeTrail.size());
	}

	// 判断蛇是否吃到豆子
	private boolean isEat() {
		return mSnakeTrail.get(mSnakeTrail.size() - 1)
				.equals(mAppleList.get(0));
	}

	// 判断是否到边界或者碰到自己的身体
	private boolean isEndGame() {
		int x = mSnakeTrail.get(headIndex).x;
		int y = mSnakeTrail.get(headIndex).y;
		if (touchBody() || x < 0 || x > 39 || y < 0 || y > 39) {
			afterEndGame();
			return true;
		}
		return false;
	}

	// 碰到自己身体
	private boolean touchBody() {
		for (int i = 0; i < mSnakeTrail.size() - 1; i++) {
			if (mSnakeTrail.get(headIndex).equals(mSnakeTrail.get(i))) {
				return true;
			}
		}
		return false;
	}

	// 游戏结束处理
	private void afterEndGame() {
		mSnakeTrail.remove(headIndex);
		panel.getSnake().setEnd(true);
		panel.repaint();
		this.isDraw = true;
	}

	Runnable runnable=new Runnable(){public void run(){moveRight();while(!isEndGame()){if(mNextDirection==Dir.UP)moveUp();else if(mNextDirection==Dir.DOWN)moveDown();else if(mNextDirection==Dir.LEFT)moveLeft();else if(mNextDirection==Dir.RIGHT)moveRight();

	try{Thread.sleep(200);}catch(InterruptedException e){e.printStackTrace();}}}

	};
}
